﻿<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

  <head>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
    <title>Background Jobs and Workers</title>
    <link type="text/css" rel="stylesheet" href="bootstrap.min.css" />
    <style type="text/css">
.auto-style1 {
  font-weight: bold;
}
    </style>
  </head>

  <body>

    <div class="document-contents">

      <h3>Introduction</h3>
      <p>ASP.NET Boilerplate provides background jobs and workers those are used 
  to execute some tasks in <strong>background threads</strong> in an 
  application.</p>

      <h3>Background Jobs</h3>
      <p>Background jobs are used to queue some tasks to be executed in background 
  in a <strong>queued and persistent</strong> manner. You may need background 
  jobs for several reasons. Some examples:</p>
      <ul>
        <li>To perform <strong>long-running tasks</strong> to not wait users. 
    For example; A user presses a 'report' button to start a long running 
    reporting job. You add this job to the <strong>queue</strong> and send 
    report result to your user via email when it's completed.</li>
        <li>To create <strong>re-trying</strong> and <strong>persistent tasks</strong> 
    to <b>g</b><span class="auto-style1">uarantee</span> a code will be
          <strong>successfully executed</strong>. 
    For example; You can send emails in a background job to overcome <strong>
    temporary failures</strong> and <strong>guarantie</strong> that it's 
    eventually will be sent. Also, thus, users do not wait while sending 
    emails.</li>
      </ul>

      <div class="bs-callout bs-callout-warning">
        <h4>About Job Persistence</h4>
        <p>See <em>Background Job Store</em> section for more information on job 
  persistence.</p>
      </div>

      <h4>Create a Background Job</h4>
      <p>We can create a background job class by either inheriting from <strong>
  BackgroundJob&lt;TArgs&gt;</strong> class or directly implementing <strong>
  IBackgroundJob&lt;TArgs&gt; interface</strong>.</p>
      <p>Here is the most simple background job:</p>
      <pre lang="cs">public class TestJob : <strong>BackgroundJob&lt;int&gt;, ITransientDependency</strong>
{
    public override void <strong>Execute</strong>(int number)
    {
        Logger.Debug(number.ToString());
    }
}</pre>
      <p>A background job defines an <strong>Execute</strong> method gets an 
  input <strong>argument</strong>. Argument <strong>type</strong> is defined 
  as <strong>generic</strong> 
  class parameter as shown in the example.</p>
      <p>A background job must be registered to
        <a href="/Pages/Documents/Dependency-Injection">dependency injection</a>. 
  Implementing <strong>ITransientDependency</strong> is the simplest way.</p>
      <p>Lest's define a more realistic job which sends emails in a background 
  queue:</p>
      <pre lang="cs">public class SimpleSendEmailJob : <strong>BackgroundJob&lt;SimpleSendEmailJobArgs&gt;, ITransientDependency</strong>
{
    private readonly IRepository&lt;User, long&gt; _userRepository;
    private readonly IEmailSender _emailSender;

    public SimpleSendEmailJob(IRepository&lt;User, long&gt; userRepository, IEmailSender emailSender)
    {
        _userRepository = userRepository;
        _emailSender = emailSender;
    }

    public override void <strong>Execute</strong>(SimpleSendEmailJobArgs args)
    {
        var senderUser = _userRepository.Get(args.SenderUserId);
        var targetUser = _userRepository.Get(args.TargetUserId);

        _emailSender.Send(senderUser.EmailAddress, targetUser.EmailAddress, args.Subject, args.Body);
    }
}</pre>
      <p>We
        <a href="/Pages/Documents/Dependency-Injection#DocConstructorInjection">
  injected</a> user <a href="/Pages/Documents/Repositories">repository</a> (to 
  get user emails) and email sender (a service to send emails) and simply sent 
  the email. <strong>SimpleSendEmailJobArgs</strong> is the job argument here and defined as 
  shown below:</p>
      <pre lang="cs">[Serializable]
public class SimpleSendEmailJobArgs
{
    public long SenderUserId { get; set; }

    public long TargetUserId { get; set; }

    public string Subject { get; set; }

    public string Body { get; set; }
}</pre>
      <p>A job argument should be <strong>serializable</strong>, because it's
        <strong>serialized and stored</strong> in the database. While ASP.NET 
  Boilerplate default background job manager uses <strong>JSON</strong> 
  serialization (which does not need [Serializable] attribute), it's better to 
  define <strong>[Serializable]</strong> attribute since we may switch to 
  another job manager in the future, which may use .NET's built-in binary serialization.</p>
      <p>
        <strong>Keep your arguments simple</strong> (like
		<a href="Data-Transfer-Objects.html">DTO</a>s), do not include
        <a href="/Pages/Documents/Entities">entities</a> or other non serializable 
  objects. As shown in the SimpleSendEmailJob sample, we can only store
        <strong>Id</strong> of an entity and get the entity from repository inside 
  the job.</p>
      <h4>Add a New Job To the Queue</h4>
      <p>After defining a background job, we can inject and use <strong>IBackgroundJobManager</strong> 
  to add a job to the queue. See a sample for TestJob defined above:</p>
      <pre lang="cs">public class MyService
{
    private readonly IBackgroundJobManager _backgroundJobManager;

    public MyService(<strong>IBackgroundJobManager backgroundJobManager</strong>)
    {
        _backgroundJobManager = backgroundJobManager;
    }

    public void Test()
    {
        <strong>_backgroundJobManager.Enqueue&lt;TestJob, int&gt;(42);</strong>
    }
}</pre>
      <p>We sent 42 as argument while enqueuing. IBackgroundJobManager will 
  instantiate and execute the TestJob with 42 as argument.</p>
      <p>Let's see to add a new job for SimpleSendEmailJob defined above:</p>
      <pre lang="cs">[AbpAuthorize]
public class MyEmailAppService : ApplicationService, IMyEmailAppService
{
    private readonly IBackgroundJobManager _backgroundJobManager;

    public MyEmailAppService(IBackgroundJobManager backgroundJobManager)
    {
        _backgroundJobManager = backgroundJobManager;
    }

    public async Task SendEmail(SendEmailInput input)
    {
            <strong>await _backgroundJobManager.EnqueueAsync&lt;SimpleSendEmailJob, SimpleSendEmailJobArgs&gt;(
            new SimpleSendEmailJobArgs
            {
                Subject = input.Subject,
                Body = input.Body,
                SenderUserId = AbpSession.GetUserId(),
                TargetUserId = input.TargetUserId
            });</strong>
    }
}</pre>
      <p>Enqueu (or EnqueueAsync) method has other parameters such as <strong>priority</strong> 
and <strong>delay</strong>.</p>
      <h4>Default Background Job Manager</h4>
      <p>IBackgroundJobManager is implemented by <strong>BackgroundJobManager</strong> 
  default. It can be replaced by another background job provider (see 
	  <a href="Hangfire-Integration.html">hangfire 
  integration</a>). Some information on default BackgroundJobManager:</p>
      <ul>
        <li>It's a simple job queue works as <strong>FIFO</strong> in a <strong>
    single thread</strong>. It uses <strong>IBackgroundJobStore</strong> to 
    persist jobs (see next section).</li>
        <li>It <strong>retries </strong>job execution until job <strong>
    successfully runs</strong> (does not throw any exception but logs them) or <strong>
    timeouts</strong>. Default 
    timeout is 2 days for a job.</li>
        <li>It <strong>deletes</strong> a job from store (database) when it's 
    successfully executed. If it's timed out, sets as <strong>abandoned</strong> and 
    leaves on the database.</li>
        <li>It <strong>increasingly waits between retries</strong> for a job. 
    Waits 1 minute for first retry, 2 minutes for second retry, 4 minutes 
    for third retry and so on..</li>
        <li>It <strong>polls</strong> the store for jobs in fixed intervals. 
    Queries jobs ordering by priority (asc) then by try count (asc).</li>
      </ul>
      <h5>Background Job Store</h5>
      <p>Default BackgroundJobManager needs a data store to save and get jobs. If 
  you do not implement <strong>IBackgroundJobStore</strong> then it uses
        <strong>InMemoryBackgroundJobStore</strong> which does not save jobs in a 
  persistent database. You can simply implement it to store jobs in a database 
  or you can use <strong>
          <a href="/Pages/Documents/Zero/Overall">module-zero</a>
        </strong> 
  which already implements it.</p>
      <p>If you are using a 3rd party job manager (like 
	  <a href="Hangfire-Integration.html">Hanfgire</a>), no need to 
  implement IBackgroundJobStore.</p>
      <h4>Configuration</h4>
      <p>You can use <strong>Configuration.BackgroundJobs</strong> in
        <a href="/Pages/Documents/Module-System">PreInitialize</a> method of your 
  module to configure background job system.</p>
      <h5>Disabling Job Execution</h5>
      <p>You may want to disable background job execution for your application:</p>
      <pre>public class MyProjectWebModule : AbpModule
{
    public override void PreInitialize()
    {
        <strong>Configuration.BackgroundJobs.IsJobExecutionEnabled = false;</strong>
    }

    //...
}</pre>
      <p>This is rarely needed. But, think that you are running multiple instances 
  of your application working on the same database (in a web farm). In this 
  case, each application will query same database for jobs and executes them. 
  This leads multiple execution of same jobs and some other problems. To 
  prevent it, you have two options:</p>
      <ul>
        <li>You can enable job execution for only one instance of the 
    application.</li>
        <li>You can disable job execution for all instances of the web 
    application and create a seperated standalone application (example: a 
    Windows Service) that executes background jobs.</li>
      </ul>
        <h4>Exception Handling</h4>
		<p>Since default background job manager should re-try failed jobs, it 
		handles (and logs) all exceptions. In case you want to be informed when 
		an exception occurred, you can create an event handler to handle
		<a href="Handling-Exceptions.html">AbpHandledExceptionData</a>. 
		Background manager triggers this event with a BackgroundJobException 
		exception object which wraps the real exception (get InnerException for 
		the actual exception).</p>
      <h4>Hangfire Integration</h4>
      <p>Background job manager is designed as <strong>replaceable</strong> by 
  another background job manager. See
        <a href="/Pages/Documents/Hangfire-Integration">hangfire integration 
  document</a> to replace it by <a href="http://hangfire.io/" target="_blank">
          <strong>Hangfire</strong>
        </a>.</p>
      <h3>Background Workers</h3>
      <p>Background workers are different than background jobs. They are simple <strong>
  independent threads</strong> in the application running in the background. 
  Generally, they run <strong>periodically</strong> to perform some tasks. 
  Examples;</p>
      <ul>
        <li>A background worker can run <strong>periodically</strong> to <strong>
    delete old logs</strong>.</li>
        <li>A background worker can <strong>periodically</strong> to <strong>
    determine inactive users</strong> and send emails to return back to your 
    application.</li>
      </ul>
      <h4>Create a Background Worker</h4>
      <p>To create a background worker, we should implement <strong>
  IBackgroundWorker</strong> interface. Alternatively, we can inherit from
        <strong>BackgroundWorkerBase</strong> or <strong>
  PeriodicBackgroundWorkerBase</strong> based on our needs.</p>
      <p>Assume that we want to make a user passive, if he did not login to the 
  application in last 30 days. See the code:</p>
      <pre lang="cs">public class MakeInactiveUsersPassiveWorker : <strong>PeriodicBackgroundWorkerBase, ISingletonDependency</strong>
{
    private readonly IRepository&lt;User, long&gt; _userRepository;

    public MakeInactiveUsersPassiveWorker(<strong>AbpTimer timer</strong>, IRepository&lt;User, long&gt; userRepository)
        <strong>: base(timer)</strong>
    {
        _userRepository = userRepository;
        <strong>Timer.Period = 5000;</strong> //5 seconds (good for tests, but normally will be more)
    }

    [UnitOfWork]
    <strong>protected override void DoWork()</strong>
    {
        using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.MayHaveTenant))
        {
            var oneMonthAgo = Clock.Now.Subtract(TimeSpan.FromDays(30));

            var inactiveUsers = _userRepository.GetAllList(u =&gt;
                u.IsActive &amp;&amp;
                ((u.LastLoginTime &lt; oneMonthAgo &amp;&amp; u.LastLoginTime != null) || (u.CreationTime &lt; oneMonthAgo &amp;&amp; u.LastLoginTime == null))
                );

            foreach (var inactiveUser in inactiveUsers)
            {
                inactiveUser.IsActive = false;
                Logger.Info(inactiveUser + &quot; made passive since he/she did not login in last 30 days.&quot;);
            }

            CurrentUnitOfWork.SaveChanges();
        }
    }
}</pre>
      <p>This is a real code and directly works in ASP.NET Boilerplate with
        <a href="/Pages/Documents/Zero/Overall">module-zero</a>.</p>
      <ul>
        <li>If you derive from <strong>PeriodicBackgroundWorkerBase</strong> (as 
    in this sample), you should implement <strong>DoWork</strong> method to 
    perform your periodic working code.</li>
        <li>If you derive from <strong>BackgroundWorkerBase</strong> or directly 
    implement <strong>IBackgroundWorke</strong>r, you will 
    override/implement <strong>Start</strong>, <strong>Stop</strong> and <strong>WaitToStop</strong> methods. 
    Start and Stop methods should be <strong>non-blocking</strong>, 
    WaitToStop method should <strong>wait</strong> worker to finish it's 
    current critical job.</li>
      </ul>
      <h4>Register Background Workers</h4>
      <p>After creating a background worker, we should add it to <strong>
  IBackgroundWorkerManager</strong>. Most common place is the 
  PostInitialize method of your module:</p>
      <pre lang="cs">public class MyProjectWebModule : AbpModule
{
    //...

    public override void PostInitialize()
    {
        var workManager = IocManager.Resolve&lt;IBackgroundWorkerManager&gt;();
        <strong>workManager.Add(IocManager.Resolve&lt;MakeInactiveUsersPassiveWorker&gt;());</strong>
    }
}</pre>
      <p>While we generally add workers in PostInitialize, there is no restriction on 
that. You can inject IBackgroundWorkerManager anywhere and add workers on 
runtime. IBackgroundWorkerManager will stop and release all registered workers 
when your applications is being shutdown.</p>
      <h4>Background Worker Lifestyles</h4>
      <p>Background workers are generally implemented as <strong>singleton</strong>. 
  But there is no restriction. If you need multiple instance of same worker 
  class, you can make it transient and add more than one instance to
  IBackgroundWorkerManager. In this case, your worker probably will be 
  parametric (say that you have a single LogCleaner class but two LogCleaner 
  worker instances they watch and clear different log folders).</p>
		<h4>Advanced Scheduling</h4>
		<p>ASP.NET Boilerplate's background worker system are simple. It has not 
		a schedule system, except periodic running workers as demonstrated 
		above. If you need to more advanced scheduling features, we suggest you 
		to check <a href="Quartz-Integration.html">Quartz</a> or another 
		library.</p>
      <h3>Making Your Application Always Running</h3>
      <p>Background jobs and workers only works if your application is running. An 
  ASP.NET application <strong>shutdowns</strong> by default if no request is 
  performed to the web application for a long time. So, if you host background 
  job execution in your web application (this is the default behaviour), you 
  should ensure that your web application is configured to always running. 
  Otherwise, background jobs only works while your applications is in use.</p>
      <p>There are some techniques to accomplish that. Most simple way is to make 
  periodic requests to your web application from an external application. 
  Thus, you can also check if your web application is up and running.
        <a href="http://docs.hangfire.io/en/latest/deployment-to-production/making-aspnet-app-always-running.html" target="_blank">
  Hangfire documentation</a> explains some other ways.</p>

    </div>

  </body>

</html>
